package playn101.core;

import static playn.core.PlayN.*;
import java.util.ArrayList;

import playn.core.Game;
import playn.core.Image;
import playn.core.ImageLayer;
import playn.core.GroupLayer;
import playn.core.Pointer;
import playn.core.Canvas;
import playn.core.CanvasImage;
import playn.core.CanvasLayer;

import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.World;
import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;


public class H implements Game {
  CanvasImage bgImage;
  ImageLayer bgLayer;
  Image cloudImage;
  ImageLayer cloudLayer;
  float x;
  float y;
  Image ballImage;
  GroupLayer ballLayer;
  GroupLayer levelLayer;

  World world;
  Body ground;

  class Ball {
    public ImageLayer layer;
    float angle = 0.0f;
    Body body;
    public Ball(Image image, float x, float y) {
      float radius = 0.5f;
      layer = graphics().createImageLayer(image);
      layer.setOrigin(image.width() / 2f, image.height() / 2f);
      layer.setScale((radius * 2) / image.width(), (radius * 2) / image.height());
      layer.setTranslation(x, y);

      BodyDef bodyDef = new BodyDef();
      bodyDef.type = BodyType.DYNAMIC;
      bodyDef.position = new Vec2(x, y);
      body = world.createBody(bodyDef);
      FixtureDef fixtureDef = new FixtureDef();
      fixtureDef.shape = new CircleShape();
      fixtureDef.shape.m_radius = radius;
      fixtureDef.density = 1.0f;
      fixtureDef.friction = 0.3f;
      body.createFixture(fixtureDef);
      body.setTransform(new Vec2(x, y), angle);
    }
    public void paint(float delta) {
      layer.setTranslation(body.getPosition().x, body.getPosition().y);
      angle += delta * 0.1f;
      layer.setRotation(angle);
    }
  }
  ArrayList<Ball> balls = new ArrayList<Ball>();
  float physUnitPerScreenUnit = 1 / 26.666667f;
  int width = 640;
  int height = 480;
  float pWidth = physUnitPerScreenUnit * width;
  float pHeight = physUnitPerScreenUnit * height;
  Canvas canvas;

  @Override
  public void init() {
    bgImage = graphics().createImage(width, height);
    canvas = bgImage.canvas();
    canvas.setFillColor(0xff87ceeb);
    canvas.fillRect(0, 0, width, height);

    bgLayer = graphics().createImageLayer(bgImage);
    graphics().rootLayer().add(bgLayer);

    cloudImage = assetManager().getImage("images/cloud.png");
    cloudLayer = graphics().createImageLayer(cloudImage);
    graphics().rootLayer().add(cloudLayer);
    x = 24.0f;
    y = 3.0f;
    ballImage = assetManager().getImage("images/ball.png");
    ballLayer = graphics().createGroupLayer();
    ballLayer.setScale(1f / physUnitPerScreenUnit);
    graphics().rootLayer().add(ballLayer);
    pointer().setListener(new Pointer.Adapter() {
      @Override
      public void onPointerEnd(Pointer.Event event) {
	Ball ball = new Ball(ballImage, physUnitPerScreenUnit * event.x(),
			     physUnitPerScreenUnit * event.y());
	balls.add(ball);
	ballLayer.add(ball.layer);
      }
    });
    initWorld();
    initBlocks();
    initNails();
  }

  public void initWorld() {
    Vec2 gravity = new Vec2(0.0f, 10.0f);
    world = new World(gravity, true);
    world.setWarmStarting(true);
    world.setAutoClearForces(true);

    ground = world.createBody(new BodyDef());
    PolygonShape bottom = new PolygonShape();
    bottom.setAsEdge(new Vec2(0, pHeight), new Vec2(pWidth, pHeight));
    ground.createFixture(bottom, 0.0f);

    PolygonShape top  = new PolygonShape();
    top.setAsEdge(new Vec2(0, 0), new Vec2(pWidth, 0));
    ground.createFixture(top, 0.0f);

    PolygonShape left = new PolygonShape();
    left.setAsEdge(new Vec2(0, 0), new Vec2(0, pHeight));
    ground.createFixture(left, 0.0f);

    PolygonShape right = new PolygonShape();
    right.setAsEdge(new Vec2(pWidth, 0), new Vec2(pWidth, pHeight));
    ground.createFixture(right, 0.0f);
  }

  public void initBlocks() {
    levelLayer = graphics().createGroupLayer();
    graphics().rootLayer().add(levelLayer);
    Image blockImage = assetManager().getImage("images/block.png");    
    for (int x = blockImage.width(); x < bgImage.width()-blockImage.width(); x+=2*blockImage.width()) {
      ImageLayer block = graphics().createImageLayer(blockImage);
      block.setTranslation(x, height-blockImage.height());
      levelLayer.add(block);
      PolygonShape blockShape = new PolygonShape();
      blockShape.setAsBox(blockImage.width()*physUnitPerScreenUnit*0.5f,
			  blockImage.height()*physUnitPerScreenUnit*0.5f,
			  new Vec2(x*physUnitPerScreenUnit+blockImage.width()*physUnitPerScreenUnit*0.5f, pHeight-blockImage.height()*physUnitPerScreenUnit*0.5f),
			  0f);
      ground.createFixture(blockShape, 0.0f);
    }
  }

  public void initNails() {
    float radius = 5f;
    float restitution = 0.6f;
    for (int x = 100; x < bgImage.width() - 100; x += 50) {
      for (int y = 150; y < 450; y+= 100) {
	canvas.setFillColor(0xff000000);
	canvas.fillCircle(x, y, radius);
	canvas.setFillColor(0xffaaaaaa);
	canvas.fillCircle(x+1, y+1, radius);
	CircleShape circleShape = new CircleShape();
	circleShape.m_radius = radius*physUnitPerScreenUnit;
	circleShape.m_p.set(x*physUnitPerScreenUnit, y*physUnitPerScreenUnit);
	FixtureDef fixtureDef = new FixtureDef();
	fixtureDef.shape = circleShape;
	fixtureDef.restitution = restitution;
	ground.createFixture(fixtureDef);
      }
    }
    for (int x = 75; x < bgImage.width() - 75; x += 50) {
      for (int y = 200; y < 400; y+= 100) {
	canvas.setFillColor(0xff000000);
	canvas.fillCircle(x, y, radius);
	canvas.setFillColor(0xffaaaaaa);
	canvas.fillCircle(x+1, y+1, radius);
	CircleShape circleShape = new CircleShape();
	circleShape.m_radius = radius*physUnitPerScreenUnit;
	circleShape.m_p.set(x*physUnitPerScreenUnit, y*physUnitPerScreenUnit);
	FixtureDef fixtureDef = new FixtureDef();
	fixtureDef.shape = circleShape;
	fixtureDef.restitution = restitution;
	ground.createFixture(fixtureDef);
      }
    }
  }

  @Override
  public void paint(float delta) {
    x += delta;
    if (x > bgImage.width() + cloudImage.width()) {
      x = -cloudImage.width();
    }
    cloudLayer.setTranslation(x, y);
    for (Ball ball : balls) {
      ball.paint(delta);
    }
  }

  @Override
  public void update(float delta) {
    world.step(0.033f, 10, 10);
  }

  @Override
  public int updateRate() {
    return 25;
  }
}
